package cn.jbolt.core.poi.excel;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Okv;
import com.jfinal.plugin.activerecord.Model;
import com.jfinal.plugin.activerecord.Record;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Excel中的一个Sheet
 *
 * @ClassName: JBoltExcelSheetSheet
 * @author: JFinal学院-小木 QQ：909854136
 * @date: 2020年4月27日
 */
public class JBoltExcelSheet {
	/**
	 * JBoltExcel 实体对象
	 */
	private JBoltExcel excel;
	/**
	 * sheet名字
	 */
	private String name;
	/**
	 * sheet 索引 第几个 从1开始
	 */
	private int sheetIndex;
	/**
	 * 合并设置
	 */
	private List<JBoltExcelMerge> merges;
	/**
	 * 表头映射
	 */
	private List<JBoltExcelHeader> headers;
	/**
	 * 主体数据
	 */
	private List<JBoltExcelData> datas;
	/**
	 * 依赖定位的数据
	 */
	private List<JBoltExcelPositionData> positionDatas;
	/**
	 * 依赖定位的公式数据
	 */
	private List<JBoltExcelPositionData> cellFormluas;
	/**
	 * 模板里需要变更位置的区域数据配置
	 */
	private List<JBoltExcelPositionChange> positionChanges;
	/**
	 * 这是需要特殊处理的单元格样式
	 */
	private List<JBoltCellStyle> cellStyles;
	/**
	 * 用merge代替了header内容设置
	 */
	private boolean mergeAsHeader;
	/**
	 * header开始的行
	 */
	private int headerStartRow;
	/**
	 * 是否需要处理header别名
	 */
	private boolean processHeaderAlias;
	/**
	 * 数据开始的行
	 */
	private int dataStartRow;
	/**
	 * 是否强制执行公式
	 */
	private boolean forceFormulaRecalculation;
	/**
	 * 数据处理器
	 */
	private JBoltExcelDataChangeHandler dataChangeHandler;
	/**
	 * 数据处理器
	 */
	private JBoltExcelDataFilter dataFilter;
	/**
	 * 整体样式处理器
	 */
	private JBoltExcelStyleHandler styleHandler;
	/**
	 * cell样式处理器
	 */
	private JBoltExcelCellStyleHandler cellStyleHandler;
	/**
	 * 水印
	 */
	private JBoltWaterMark waterMark;

	/**
	 * 创建sheet 默认sheet索引 1
	 *
	 * @return
	 */
	public static JBoltExcelSheet create() {
		return create(1);
	}

	/**
	 * 创建sheet 指定sheet索引 从1开始
	 *
	 * @param sheetIndex
	 * @return
	 */
	public static JBoltExcelSheet create(int sheetIndex) {
		return new JBoltExcelSheet(sheetIndex);
	}

	/**
	 * 创建sheet 指定sheet名字
	 *
	 * @param name
	 * @return
	 */
	public static JBoltExcelSheet create(String name) {
		return new JBoltExcelSheet(name);
	}

	/**
	 * 构造函数
	 *
	 * @param name
	 */
	private JBoltExcelSheet(String name) {
		this.name = name;
		this.mergeAsHeader = false;
		this.headerStartRow = 0;
		this.dataStartRow = 0;
	}

	/**
	 * 构造函数
	 *
	 * @param sheetIndex
	 */
	private JBoltExcelSheet(int sheetIndex) {
		this.sheetIndex = sheetIndex;
		this.mergeAsHeader = false;
		this.headerStartRow = 0;
		this.dataStartRow = 0;
	}

	/**
	 * 判断是否有可写出数据
	 *
	 * @return
	 */
	public boolean hasDatas() {
		return CollUtil.isNotEmpty(this.datas);
	}

	/**
	 * 判断是否有依赖定位写出的数据
	 *
	 * @return
	 */
	public boolean hasPositionDatas() {
		return CollUtil.isNotEmpty(this.positionDatas);
	}

	/**
	 * 判断是否有依赖定位写出的公式数据
	 *
	 * @return
	 */
	public boolean hasCellFormluas() {
		return CollUtil.isNotEmpty(this.cellFormluas);
	}

	/**
	 * 是否有标题设置
	 *
	 * @return
	 */
	public boolean hasHeaders() {
		return CollUtil.isNotEmpty(this.headers);
	}

	/**
	 * 是否有模板里需要变更位置的数据
	 *
	 * @return
	 */
	public boolean hasPositionChanges() {
		return CollUtil.isNotEmpty(this.positionChanges);
	}

	/**
	 * 是否有单元格合并设置
	 *
	 * @return
	 */
	public boolean hasMerges() {
		return CollUtil.isNotEmpty(this.merges);
	}

	public List<JBoltExcelMerge> getMerges() {
		return merges;
	}

	/**
	 * 设置单元格合并
	 *
	 * @param merges
	 * @return
	 */
	public JBoltExcelSheet setMerges(List<JBoltExcelMerge> merges) {
		this.merges = merges;
		return this;
	}

	/**
	 * 设置单元格合并
	 *
	 * @param merges
	 * @return
	 */
	public JBoltExcelSheet setMerges(JBoltExcelMerge... merges) {
		return setMerges(ListUtil.toList(merges));
	}

	/**
	 * 追加单元格合并配置
	 *
	 * @param merges
	 * @return
	 */
	public JBoltExcelSheet addMerges(List<JBoltExcelMerge> merges) {
		if (merges != null && merges.size() > 0) {
			if (hasMerges()) {
				this.merges.addAll(merges);
			} else {
				setMerges(merges);
			}
		}
		return this;
	}

	/**
	 * 追加单元格合并配置
	 *
	 * @param merges
	 * @return
	 */
	public JBoltExcelSheet addMerges(JBoltExcelMerge... merges) {
		return addMerges(ListUtil.toList(merges));
	}

	/**
	 * 获取表格数据
	 *
	 * @return
	 */
	public List<JBoltExcelData> getDatas() {
		return datas;
	}

	/**
	 * 设置表格数据
	 *
	 * @param datas
	 * @return
	 */
	public JBoltExcelSheet setDatas(List<JBoltExcelData> datas) {
		this.datas = datas;
		return this;
	}

	/**
	 * 设置model数据
	 *
	 * @param dataStartRow 数据开始行 从1开始
	 * @param models
	 * @return
	 */
	public JBoltExcelSheet setModelDatas(int dataStartRow, List<? extends Model<?>> models) {
		setDataStartRow(dataStartRow);
		if (models != null && models.size() > 0) {
			this.datas = new ArrayList<JBoltExcelData>();
			for (Model<?> model : models) {
				this.datas.add(JBoltExcelData.fromModel(model));
			}
		}
		return this;
	}

	/**
	 * 设置数据变更处理器
	 *
	 * @param dataChangeHandler
	 * @return
	 */
	public JBoltExcelSheet setDataChangeHandler(JBoltExcelDataChangeHandler dataChangeHandler) {
		this.dataChangeHandler = dataChangeHandler;
		return this;
	}

	/**
	 * 设置数据过滤器 一般用在读取指定数据 或者导出数据再过滤一次
	 * @param dataFilter
	 * @return
	 */
	public JBoltExcelSheet setDataFilter(JBoltExcelDataFilter dataFilter){
		this.dataFilter = dataFilter;
		return this;
	}

	/**
	 * 设置样式处理器
	 *
	 * @param styleHandler
	 * @return
	 */
	public JBoltExcelSheet setStyleHandler(JBoltExcelStyleHandler styleHandler) {
		this.styleHandler = styleHandler;
		return this;
	}

	/**
	 * 设置records数据
	 *
	 * @param dataStartRow
	 * @param records
	 * @return
	 */
	public JBoltExcelSheet setRecordDatas(int dataStartRow, List<Record> records) {
		setDataStartRow(dataStartRow);
		if (records != null && records.size() > 0) {
			this.datas = new ArrayList<JBoltExcelData>();
			for (Record record : records) {
				this.datas.add(JBoltExcelData.fromRecord(record));
			}
		}
		return this;
	}

	/**
	 * 获取表头配置
	 *
	 * @return
	 */
	public List<JBoltExcelHeader> getHeaders() {
		return headers;
	}

	/**
	 * 获取表头设置列
	 *
	 * @return
	 */
	public List<String> getHeaderColumns() {
		if (headers == null || headers.size() == 0) {
			return null;
		}
		List<String> columns = new ArrayList<String>();
		headers.forEach((h) -> {
			columns.add(h.getColumn());
		});
		return columns;
	}

	/**
	 * 获取表头设置内容
	 *
	 * @return
	 */
	public List<String> getHeaderContents() {
		if (headers == null || headers.size() == 0) {
			return null;
		}
		List<String> contents = new ArrayList<String>();
		headers.forEach((h) -> {
			contents.add(h.getContent());
		});
		return contents;
	}

	/**
	 * 设置表头配置
	 *
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(List<JBoltExcelHeader> headers) {
		return setHeaders(0, headers);
	}

	/**
	 * 设置表头配置
	 *
	 * @param headerStartRow 数据开始行 从1开始
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(int headerStartRow, List<JBoltExcelHeader> headers) {
		return setHeaders(headerStartRow, true, headers);
	}
	/**
	 * 设置Headers
	 *
	 * @param processHeaderAlias
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(boolean processHeaderAlias, List<JBoltExcelHeader> headers) {
		return setHeaders(0,processHeaderAlias,headers);
	}
	/**
	 * 设置Headers
	 *
	 * @param headerStartRow     数据开始行 从1开始
	 * @param processHeaderAlias
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(int headerStartRow, boolean processHeaderAlias, List<JBoltExcelHeader> headers) {
		this.headers = headers;
		this.headerStartRow = headerStartRow;
		this.processHeaderAlias = processHeaderAlias;
		return this;
	}

	/**
	 * 设置表头配置
	 *
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(JBoltExcelHeader... headers) {
		return setHeaders(1, headers);
	}

	/**
	 * 设置表头配置
	 *
	 * @param headerStartRow
	 * @param processHeaderAlias
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(int headerStartRow, boolean processHeaderAlias, JBoltExcelHeader... headers) {
		return setHeaders(headerStartRow, processHeaderAlias, ListUtil.toList(headers));
	}

	/**
	 * 设置表头配置
	 *
	 * @param processHeaderAlias
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(boolean processHeaderAlias, JBoltExcelHeader... headers) {
		return setHeaders(0, processHeaderAlias, headers);
	}

	/**
	 * 设置表头配置
	 *
	 * @param headerStartRow
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet setHeaders(int headerStartRow, JBoltExcelHeader... headers) {
		return setHeaders(headerStartRow, true, headers);
	}

	/**
	 * 追加表头设置
	 *
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet addHeaders(List<JBoltExcelHeader> headers) {
		if (headers != null && headers.size() > 0) {
			if (hasHeaders()) {
				this.headers.addAll(headers);
			} else {
				setHeaders(headers);
			}
		}
		return this;
	}

	/**
	 * 追加表头配置
	 *
	 * @param headers
	 * @return
	 */
	public JBoltExcelSheet addHeaders(JBoltExcelHeader... headers) {
		return addHeaders(ListUtil.toList(headers));
	}

	/**
	 * 判断是否用merge代替了header内容设置
	 *
	 * @return
	 */
	public boolean isMergeAsHeader() {
		return mergeAsHeader;
	}

	public JBoltExcelSheet setMergeAsHeader(boolean mergeAsHeader) {
		this.mergeAsHeader = mergeAsHeader;
		return this;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public JBoltExcelDataChangeHandler getDataChangeHandler() {
		return dataChangeHandler;
	}

	public JBoltExcelDataFilter getDataFilter() {
		return dataFilter;
	}

	public int getHeaderStartRow() {
		return headerStartRow;
	}

	public JBoltExcelSheet setHeaderStartRow(int headerStartRow) {
		this.headerStartRow = headerStartRow;
		return this;
	}

	public int getDataStartRow() {
		return dataStartRow;
	}

	public JBoltExcelSheet setDataStartRow(int dataStartRow) {
		this.dataStartRow = dataStartRow;
		return this;
	}

	public boolean isProcessHeaderAlias() {
		return processHeaderAlias;
	}

	public void setProcessHeaderAlias(boolean processHeaderAlias) {
		this.processHeaderAlias = processHeaderAlias;
	}

	public JBoltExcel getExcel() {
		return excel;
	}

	public void setExcel(JBoltExcel excel) {
		this.excel = excel;
	}

	/**
	 * 用List<Kv>设置数据
	 *
	 * @param dataStartRow 数据开始行 从1开始
	 * @param kvs
	 * @return
	 */
	public JBoltExcelSheet setKvDatas(int dataStartRow, List<Kv> kvs) {
		setDataStartRow(dataStartRow);
		if (kvs != null && kvs.size() > 0) {
			this.datas = new ArrayList<JBoltExcelData>();
			for (Kv kv : kvs) {
				this.datas.add(JBoltExcelData.fromKv(kv));
			}
		}
		return this;
	}

	/**
	 * 用List<Okv>设置数据
	 *
	 * @param dataStartRow 数据开始行 从1开始
	 * @param okvs
	 * @return
	 */
	public JBoltExcelSheet setOkvDatas(int dataStartRow, List<Okv> okvs) {
		setDataStartRow(dataStartRow);
		if (okvs != null && okvs.size() > 0) {
			this.datas = new ArrayList<JBoltExcelData>();
			for (Okv kv : okvs) {
				this.datas.add(JBoltExcelData.fromOkv(kv));
			}
		}
		return this;
	}

	/**
	 * 用List<Map<K,V>>设置数据
	 *
	 * @param dataStartRow
	 * @param mapDatas
	 * @return
	 */
	public JBoltExcelSheet setMapDatas(int dataStartRow, ArrayList<Map<String, Object>> mapDatas) {
		setDataStartRow(dataStartRow);
		if (mapDatas != null && mapDatas.size() > 0) {
			this.datas = new ArrayList<JBoltExcelData>();
			for (Map<String, Object> mapData : mapDatas) {
				this.datas.add(JBoltExcelData.fromMap(mapData));
			}
		}
		return this;
	}

	/**
	 * 获取定位输出数据
	 *
	 * @return
	 */
	public List<JBoltExcelPositionData> getPositionDatas() {
		return positionDatas;
	}

	/**
	 * 设置定位输出数据
	 *
	 * @param positionDatas
	 * @return
	 */
	public JBoltExcelSheet setPositionDatas(List<JBoltExcelPositionData> positionDatas) {
		positionDatas.forEach(positionData -> positionData.setValueIsFormula(false));
		this.positionDatas = positionDatas;
		return this;
	}

	/**
	 * 追加定位数据
	 *
	 * @param positionDatas
	 * @return
	 */
	public JBoltExcelSheet addPositionDatas(List<JBoltExcelPositionData> positionDatas) {
		if (positionDatas != null && positionDatas.size() > 0) {
			if (hasPositionDatas()) {
				this.positionDatas.addAll(positionDatas);
			} else {
				setPositionDatas(positionDatas);
			}
		}
		return this;
	}

	/**
	 * 添加定位输出数据
	 *
	 * @param positionDatas
	 * @return
	 */
	public JBoltExcelSheet addPositionDatas(JBoltExcelPositionData... positionDatas) {
		return addPositionDatas(ListUtil.toList(positionDatas));
	}

	/**
	 * 设置公式数据
	 *
	 * @param cellFormluas
	 * @return
	 */
	public JBoltExcelSheet setCellFormluas(List<JBoltExcelPositionData> cellFormluas) {
		cellFormluas.forEach(cellFormlua -> cellFormlua.setValueIsFormula(true));
		this.cellFormluas = cellFormluas;
		return this;
	}

	/**
	 * 添加公式数据
	 *
	 * @param cellFormluas
	 * @return
	 */
	public JBoltExcelSheet addCellFormluas(List<JBoltExcelPositionData> cellFormluas) {
		if (cellFormluas != null && cellFormluas.size() > 0) {
			if (hasCellFormluas()) {
				cellFormluas.forEach(cellFormlua -> cellFormlua.setValueIsFormula(true));
				this.cellFormluas.addAll(cellFormluas);
			} else {
				setCellFormluas(cellFormluas);
			}

			if (!forceFormulaRecalculation) {
				setForceFormulaRecalculation(true);
			}
		}
		return this;
	}

	/**
	 * 添加公式数据
	 *
	 * @param cellFormluas
	 * @return
	 */
	public JBoltExcelSheet addCellFormluas(JBoltExcelPositionData... cellFormluas) {
		return addCellFormluas(ListUtil.toLinkedList(cellFormluas));
	}

	/**
	 * 获取设置的公式
	 *
	 * @return
	 */
	public List<JBoltExcelPositionData> getCellFormluas() {
		return cellFormluas;
	}

	/**
	 * 是否强制执行公式
	 *
	 * @return
	 */
	public boolean isForceFormulaRecalculation() {
		return forceFormulaRecalculation;
	}

	/**
	 * 设置是否强制执行公式
	 *
	 * @param forceFormulaRecalculation
	 * @return
	 */
	public JBoltExcelSheet setForceFormulaRecalculation(boolean forceFormulaRecalculation) {
		this.forceFormulaRecalculation = forceFormulaRecalculation;
		return this;
	}

	/**
	 * 获取待变更定位区域
	 *
	 * @return
	 */
	public List<JBoltExcelPositionChange> getPositionChanges() {
		return positionChanges;
	}

	/**
	 * 设置待变更定位区域
	 *
	 * @param positionChanges
	 */
	public JBoltExcelSheet setPositionChanges(List<JBoltExcelPositionChange> positionChanges) {
		this.positionChanges = positionChanges;
		return this;
	}

	/**
	 * 添加待变更定位区域
	 *
	 * @param positionChanges
	 * @return
	 */
	public JBoltExcelSheet addPositionChanges(List<JBoltExcelPositionChange> positionChanges) {
		if (positionChanges != null && positionChanges.size() > 0) {
			if (hasPositionChanges()) {
				this.positionChanges.addAll(positionChanges);
			} else {
				setPositionChanges(positionChanges);
			}
		}
		return this;
	}

	/**
	 * 添加待变更定位区域
	 *
	 * @param positionChanges
	 * @return
	 */
	public JBoltExcelSheet addPositionChanges(JBoltExcelPositionChange... positionChanges) {
		return addPositionChanges(ListUtil.toList(positionChanges));
	}

	public JBoltExcelStyleHandler getStyleHandler() {
		return styleHandler;
	}

	public int getSheetIndex() {
		return sheetIndex;
	}

	public void setSheetIndex(int sheetIndex) {
		this.sheetIndex = sheetIndex;
	}

	public JBoltWaterMark getWaterMark() {
		return waterMark;
	}

	public JBoltExcelSheet setWaterMark(JBoltWaterMark waterMark) {
		this.waterMark = waterMark;
		return this;
	}

	public JBoltExcelCellStyleHandler getCellStyleHandler() {
		return cellStyleHandler;
	}

	public JBoltExcelSheet setCellStyleHandler(JBoltExcelCellStyleHandler cellStyleHandler) {
		this.cellStyleHandler = cellStyleHandler;
		return this;
	}

	public List<JBoltCellStyle> getCellStyles() {
		return cellStyles;
	}

	public JBoltExcelSheet setCellStyles(List<JBoltCellStyle> cellStyles) {
		this.cellStyles = cellStyles;
		return this;
	}

	public JBoltExcelSheet addCellStyles(List<JBoltCellStyle> cellStyles) {
		if (this.cellStyles == null) {
			return setCellStyles(cellStyles);
		}
		this.cellStyles.addAll(cellStyles);
		return this;
	}

	public JBoltExcelSheet addCellStyle(JBoltCellStyle cellStyle) {
		if (this.cellStyles == null) {
			this.cellStyles = new ArrayList<JBoltCellStyle>();
		}
		this.cellStyles.add(cellStyle);
		return this;
	}

	public boolean hasCellStyles() {
		return this.cellStyles != null && this.cellStyles.size() > 0;
	}

}
